From fe0b8e6e6e4d5802c18f214e73a4d5fdda3631fa Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Fri, 5 Aug 2005 08:59:41 +0000 Subject: [PATCH] The attached patch: 1. Converts the shutdown driver and xend to use the store instead of control messages, 2. Includes Anthony's xenstore notification code, and 3. Changes xend so that sysrq's are no longer sent as "special case" shutdown messages. Store keys are cheap, so making the sysrq delivery less obscure is good. I think I have made all of the appropriate modifications to Xend, but it is complex, so I may have missed something. Comments are welcome. Signed-off-by: Dan Smith Signed-off-by: Anthony Liguori --- linux-2.6-xen-sparse/arch/xen/kernel/reboot.c | 125 +++++++++++++----- .../drivers/xen/xenbus/xenbus_probe.c | 35 +++++ linux-2.6-xen-sparse/include/asm-xen/xenbus.h | 5 + tools/python/xen/xend/XendClient.py | 10 +- tools/python/xen/xend/XendDomain.py | 13 +- tools/python/xen/xend/XendDomainInfo.py | 38 +++--- tools/python/xen/xend/server/SrvDomain.py | 12 +- tools/python/xen/xm/sysrq.py | 5 +- 8 files changed, 179 insertions(+), 64 deletions(-) diff --git a/linux-2.6-xen-sparse/arch/xen/kernel/reboot.c b/linux-2.6-xen-sparse/arch/xen/kernel/reboot.c index e56e1edcee..9447000690 100644 --- a/linux-2.6-xen-sparse/arch/xen/kernel/reboot.c +++ b/linux-2.6-xen-sparse/arch/xen/kernel/reboot.c @@ -11,7 +11,6 @@ static int errno; #include #include #include -#include #include #include #include @@ -19,6 +18,11 @@ static int errno; #include #include +#define SHUTDOWN_INVALID -1 +#define SHUTDOWN_POWEROFF 0 +#define SHUTDOWN_REBOOT 1 +#define SHUTDOWN_SUSPEND 2 + void machine_restart(char * __unused) { /* We really want to get pending console data out before we die. */ @@ -53,7 +57,7 @@ EXPORT_SYMBOL(machine_power_off); */ /* Ignore multiple shutdown requests. */ -static int shutting_down = -1; +static int shutting_down = SHUTDOWN_INVALID; static void __do_suspend(void) { @@ -126,8 +130,6 @@ static void __do_suspend(void) xenbus_suspend(); - ctrl_if_suspend(); - irq_suspend(); gnttab_suspend(); @@ -140,7 +142,7 @@ static void __do_suspend(void) HYPERVISOR_suspend(virt_to_machine(suspend_record) >> PAGE_SHIFT); - shutting_down = -1; + shutting_down = SHUTDOWN_INVALID; memcpy(&xen_start_info, &suspend_record->resume_info, sizeof(xen_start_info)); @@ -163,8 +165,6 @@ static void __do_suspend(void) irq_resume(); - ctrl_if_resume(); - xenbus_resume(); #ifdef CONFIG_SMP @@ -204,7 +204,7 @@ static int shutdown_process(void *__unused) switch ( shutting_down ) { - case CMSG_SHUTDOWN_POWEROFF: + case SHUTDOWN_POWEROFF: if ( execve("/sbin/poweroff", poweroff_argv, envp) < 0 ) { sys_reboot(LINUX_REBOOT_MAGIC1, @@ -214,7 +214,7 @@ static int shutdown_process(void *__unused) } break; - case CMSG_SHUTDOWN_REBOOT: + case SHUTDOWN_REBOOT: if ( execve("/sbin/reboot", restart_argv, envp) < 0 ) { sys_reboot(LINUX_REBOOT_MAGIC1, @@ -225,7 +225,7 @@ static int shutdown_process(void *__unused) break; } - shutting_down = -1; /* could try again */ + shutting_down = SHUTDOWN_INVALID; /* could try again */ return 0; } @@ -234,7 +234,7 @@ static void __shutdown_handler(void *unused) { int err; - if ( shutting_down != CMSG_SHUTDOWN_SUSPEND ) + if ( shutting_down != SHUTDOWN_SUSPEND ) { err = kernel_thread(shutdown_process, NULL, CLONE_FS | CLONE_FILES); if ( err < 0 ) @@ -246,42 +246,103 @@ static void __shutdown_handler(void *unused) } } -static void shutdown_handler(ctrl_msg_t *msg, unsigned long id) +static void shutdown_handler(struct xenbus_watch *watch, const char *node) { static DECLARE_WORK(shutdown_work, __shutdown_handler, NULL); - if ( msg->subtype == CMSG_SHUTDOWN_SYSRQ ) - { - int sysrq = ((shutdown_sysrq_t *)&msg->msg[0])->key; - + int type = -1; + + if (!xenbus_scanf("control", "shutdown", "%i", &type)) { + printk("Unable to read code in control/shutdown\n"); + return; + }; + + xenbus_printf("control", "shutdown", "%i", SHUTDOWN_INVALID); + + if ((type == SHUTDOWN_POWEROFF) || + (type == SHUTDOWN_REBOOT) || + (type == SHUTDOWN_SUSPEND)) { + shutting_down = type; + schedule_work(&shutdown_work); + } + +} + #ifdef CONFIG_MAGIC_SYSRQ +static void sysrq_handler(struct xenbus_watch *watch, const char *node) +{ + char sysrq_key = '\0'; + + if (!xenbus_scanf("control", "sysrq", "%c", &sysrq_key)) { + printk("Unable to read sysrq code in control/sysrq\n"); + return; + } + + xenbus_printf("control", "sysrq", "%c", '\0'); + + if (sysrq_key != '\0') { + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) - handle_sysrq(sysrq, NULL, NULL); + handle_sysrq(sysrq_key, NULL, NULL); #else - handle_sysrq(sysrq, NULL, NULL, NULL); -#endif + handle_sysrq(sysrq_key, NULL, NULL, NULL); #endif } - else if ( (shutting_down == -1) && - ((msg->subtype == CMSG_SHUTDOWN_POWEROFF) || - (msg->subtype == CMSG_SHUTDOWN_REBOOT) || - (msg->subtype == CMSG_SHUTDOWN_SUSPEND)) ) - { - shutting_down = msg->subtype; - schedule_work(&shutdown_work); +} +#endif + +static struct xenbus_watch shutdown_watch = { + .node = "control/shutdown", + .callback = shutdown_handler +}; + +#ifdef CONFIG_MAGIC_SYSRQ +static struct xenbus_watch sysrq_watch = { + .node ="control/sysrq", + .callback = sysrq_handler +}; +#endif + +static struct notifier_block xenstore_notifier; + +static int setup_shutdown_watcher(struct notifier_block *notifier, + unsigned long event, + void *data) +{ + int err1=0, err2=0; + + down(&xenbus_lock); + err1 = register_xenbus_watch(&shutdown_watch); +#ifdef CONFIG_MAGIC_SYSRQ + err2 = register_xenbus_watch(&sysrq_watch); +#endif + up(&xenbus_lock); + + if (err1) { + printk("Failed to set shutdown watcher\n"); } - else - { - printk("Ignore spurious shutdown request\n"); + +#ifdef CONFIG_MAGIC_SYSRQ + if (err2) { + printk("Failed to set sysrq watcher\n"); } +#endif - ctrl_if_send_response(msg); + return NOTIFY_STOP; } static int __init setup_shutdown_event(void) { - ctrl_if_register_receiver(CMSG_SHUTDOWN, shutdown_handler, 0); + + xenstore_notifier.notifier_call = setup_shutdown_watcher; + + if (xen_start_info.store_evtchn) { + setup_shutdown_watcher(&xenstore_notifier, 0, NULL); + } else { + register_xenstore_notifier(&xenstore_notifier); + } + return 0; } -__initcall(setup_shutdown_event); +subsys_initcall(setup_shutdown_event); diff --git a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c index d440618f2d..706d351121 100644 --- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c +++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c @@ -36,10 +36,16 @@ #include #include #include +#include #include "xenbus_comms.h" #define streq(a, b) (strcmp((a), (b)) == 0) +/* Protects notifier chain */ +DECLARE_MUTEX(xenstore_control); + +static struct notifier_block *xenstore_chain; + /* If something in array of ids matches this device, return it. */ static const struct xenbus_device_id * match_device(const struct xenbus_device_id *arr, struct xenbus_device *dev) @@ -309,6 +315,26 @@ void xenbus_resume(void) up(&xenbus_lock); } +int register_xenstore_notifier(struct notifier_block *nb) +{ + int ret; + + if ((ret = down_interruptible(&xenstore_control)) != 0) + return ret; + ret = notifier_chain_register(&xenstore_chain, nb); + up(&xenstore_control); + return ret; +} +EXPORT_SYMBOL(register_xenstore_notifier); + +void unregister_xenstore_notifier(struct notifier_block *nb) +{ + down(&xenstore_control); + notifier_chain_unregister(&xenstore_chain, nb); + up(&xenstore_control); +} +EXPORT_SYMBOL(unregister_xenstore_notifier); + /* called from a thread in privcmd/privcmd.c */ int do_xenbus_probe(void *unused) { @@ -323,6 +349,15 @@ int do_xenbus_probe(void *unused) return err; } + err = notifier_call_chain(&xenstore_chain, 0, 0); + if (err == NOTIFY_BAD) { + printk("%s: calling xenstore notify chain failed\n", + __FUNCTION__); + return -EINVAL; + } + + err = 0; + /* Initialize non-xenbus drivers */ balloon_init_watcher(); diff --git a/linux-2.6-xen-sparse/include/asm-xen/xenbus.h b/linux-2.6-xen-sparse/include/asm-xen/xenbus.h index af205d8945..0f30dc8ebe 100644 --- a/linux-2.6-xen-sparse/include/asm-xen/xenbus.h +++ b/linux-2.6-xen-sparse/include/asm-xen/xenbus.h @@ -29,6 +29,7 @@ * IN THE SOFTWARE. */ #include +#include #include /* A xenbus device. */ @@ -112,6 +113,10 @@ struct xenbus_watch void (*callback)(struct xenbus_watch *, const char *node); }; +/* notifer routines for when the xenstore comes up */ +int register_xenstore_notifier(struct notifier_block *nb); +void unregister_xenstore_notifier(struct notifier_block *nb); + int register_xenbus_watch(struct xenbus_watch *watch); void unregister_xenbus_watch(struct xenbus_watch *watch); diff --git a/tools/python/xen/xend/XendClient.py b/tools/python/xen/xend/XendClient.py index 868836c30f..570c59d231 100644 --- a/tools/python/xen/xend/XendClient.py +++ b/tools/python/xen/xend/XendClient.py @@ -208,11 +208,15 @@ class Xend: return self.xendPost(self.domainurl(id), {'op' : 'pause' }) - def xend_domain_shutdown(self, id, reason, key=0): + def xend_domain_shutdown(self, id, reason): return self.xendPost(self.domainurl(id), {'op' : 'shutdown', - 'reason' : reason, - 'key' : key }) + 'reason' : reason}) + + def xend_domain_sysrq(self, id, key): + return self.xendPost(self.domainurl(id), + {'op' : 'sysrq', + 'key' : key}) def xend_domain_destroy(self, id, reason): return self.xendPost(self.domainurl(id), diff --git a/tools/python/xen/xend/XendDomain.py b/tools/python/xen/xend/XendDomain.py index 157d2216cf..6527f3fb5f 100644 --- a/tools/python/xen/xend/XendDomain.py +++ b/tools/python/xen/xend/XendDomain.py @@ -386,7 +386,7 @@ class XendDomain: except Exception, ex: raise XendError(str(ex)) - def domain_shutdown(self, id, reason='poweroff', key=0): + def domain_shutdown(self, id, reason='poweroff'): """Shutdown domain (nicely). - poweroff: restart according to exit code and restart mode - reboot: restart on exit @@ -402,11 +402,18 @@ class XendDomain: eserver.inject('xend.domain.shutdown', [dominfo.name, dominfo.id, reason]) if reason == 'halt': reason = 'poweroff' - val = dominfo.shutdown(reason, key=key) - if not reason in ['suspend', 'sysrq']: + val = dominfo.shutdown(reason) + if not reason in ['suspend']: self.domain_shutdowns() return val + def domain_sysrq(self, id, key): + """Send a SysRq to a domain + """ + dominfo = self.domain_lookup(id) + val = dominfo.send_sysrq(key) + return val + def domain_shutdowns(self): """Process pending domain shutdowns. Destroys domains whose shutdowns have timed out. diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index 3e016b681f..3510f79441 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -52,13 +52,12 @@ shutdown_reasons = { DOMAIN_CRASH : "crash", } -"""Map shutdown reasons to the message type to use. +"""Map shutdown reasons to codes """ -shutdown_messages = { - 'poweroff' : 'shutdown_poweroff_t', - 'reboot' : 'shutdown_reboot_t', - 'suspend' : 'shutdown_suspend_t', - 'sysrq' : 'shutdown_sysrq_t', +shutdown_codes = { + 'poweroff' : DOMAIN_POWEROFF, + 'reboot' : DOMAIN_REBOOT, + 'suspend' : DOMAIN_SUSPEND, } RESTART_ALWAYS = 'always' @@ -152,8 +151,6 @@ class XendDomainInfo: vm = cls(db) vm.construct(config) vm.saveToDB(sync=True) - # Flush info to xenstore immediately - vm.exportToDB() return vm @@ -941,19 +938,20 @@ class XendDomainInfo: self.channel.writeRequest(msg) - def shutdown(self, reason, key=0): - msgtype = shutdown_messages.get(reason) - if not msgtype: + def shutdown(self, reason): + reasonid = shutdown_codes.get(reason) + if reasonid == None: raise XendError('invalid reason:' + reason) - extra = {} - if reason == 'sysrq': - extra['key'] = key - if self.channel: - msg = messages.packMsg(msgtype, extra) - self.channel.writeRequest(msg) - if not reason in ['suspend', 'sysrq']: - self.shutdown_pending = {'start':time.time(), 'reason':reason, - 'key':key} + db = self.db.addChild("/control"); + db['shutdown'] = '%i' % reasonid; + db.saveDB(save=True); + if not reason in ['suspend']: + self.shutdown_pending = {'start':time.time(), 'reason':reason} + + def send_sysrq(self, key=0): + db = self.db.addChild("/control"); + db['sysrq'] = '%c' % key; + db.saveDB(save=True); def shutdown_time_left(self, timeout): if not self.shutdown_pending: diff --git a/tools/python/xen/xend/server/SrvDomain.py b/tools/python/xen/xend/server/SrvDomain.py index 6e51e69518..d0249dab7b 100644 --- a/tools/python/xen/xend/server/SrvDomain.py +++ b/tools/python/xen/xend/server/SrvDomain.py @@ -39,13 +39,21 @@ class SrvDomain(SrvDir): def op_shutdown(self, op, req): fn = FormFn(self.xd.domain_shutdown, [['dom', 'int'], - ['reason', 'str'], - ['key', 'int']]) + ['reason', 'str']]) val = fn(req.args, {'dom': self.dom.id}) req.setResponseCode(http.ACCEPTED) req.setHeader("Location", "%s/.." % req.prePathURL()) return val + def op_sysrq(self, op, req): + fn = FormFn(self.xd.domain_sysrq, + [['dom', 'int'], + ['key', 'int']]) + val = fn(req.args, {'dom' : self.dom.id}) + req.setResponseCode(http.ACCEPTED) + req.setHeader("Location", "%s/.." % req.prePathURL()) + return val + def op_destroy(self, op, req): fn = FormFn(self.xd.domain_destroy, [['dom', 'int'], diff --git a/tools/python/xen/xm/sysrq.py b/tools/python/xen/xm/sysrq.py index 44827af094..12b2da22fe 100644 --- a/tools/python/xen/xm/sysrq.py +++ b/tools/python/xen/xm/sysrq.py @@ -21,9 +21,6 @@ gopts.opt('help', short='h', fn=set_true, default=0, use="Print this help.") -def sysrq(dom, req): - server.xend_domain_shutdown(dom, 'sysrq', req) - def main(argv): opts = gopts args = opts.parse(argv) @@ -36,4 +33,4 @@ def main(argv): if len(args) < 2: opts.err('Missing sysrq character') dom = args[0] req = ord(args[1][0]) - sysrq(dom, req) + server.xend_domain_sysrq(dom, req) -- 2.30.2